package com.james.codeauto.util;

import com.james.codeauto.ConvertBridge;
import com.james.codeauto.common.PropertiesComponentWarpper;
import com.james.codeauto.common.StringUtils;
import com.james.codeauto.entity.ClassEntity;
import com.james.codeauto.entity.FieldApiInfo;
import com.james.codeauto.entity.FieldEntity;
import com.james.codeauto.tools.json.JSONArray;
import com.james.codeauto.tools.json.JSONException;
import com.james.codeauto.tools.json.JSONObject;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;


public class GenUtils {


    public static List<String> getTemplates() {
        List<String> templates = new ArrayList<String>();
        templates.add(".java.vm");
        templates.add("RequestDto.java.vm");
//        templates.add("Service.java.vm");
//        templates.add("ServiceImpl.java.vm");
//        templates.add("Controller.java.vm");
        templates.add("TestController.java.vm");
        templates.add("Test.java.vm");
        templates.add("Strage2Map.java.vm");
        templates.add("serviceToMap.java.vm");

        templates.add("TestMap.java.vm");
        templates.add("CouponService.java.vm");
        return templates;
    }

    public static void main(String[] args) throws Exception {

        // String query = "我要妹子！";
        // System.out.println(TransApi.getTransResultDtoName(query));


    }


    public static Map<String, Object> covertDataEntity(Map<String, Object> map, Map<String, Object> jsonData) throws Exception {
        //配置信息
        Configuration config = getConfig();
        //表信息
        AutoCodeEntity tableEntity = new AutoCodeEntity();
        tableEntity.setComments((String) jsonData.get("desc"));
        tableEntity.setClassName((String) jsonData.get("dtoName"));
        //设置velocity资源加载器
        Properties props = new Properties();
        // props.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        props.put("file.resource.loader.path", Paths.get("templatevm").toAbsolutePath().toString());
        Velocity.init(props);

        String mainPath = config.getString("mainPath");
        if (map == null) {
            map = new HashMap<>();
        }
        ConvertBridge convertBridge = new ConvertBridge();
        Object jsonObject = jsonData.get("responseJson");
        if (jsonObject != null) {
            JSONObject data = new JSONObject();
            if (jsonObject instanceof JSONArray) {
                data = ((JSONArray) jsonObject).getJSONObject(0);
            } else if (jsonObject instanceof String) {
                return null;
            } else {
                data = (JSONObject) jsonObject;
            }
            if (data == null) {
                return null;
            }
            if (StringUtils.isNotBlank(data.optString("isFirstPage"))) {
                if (data.optJSONArray("list") != null && data.optJSONArray("list").length() > 0) {
                    data = data.optJSONArray("list").optJSONObject(0);
                }
            }
            if (data.optJSONArray("datas") != null) {
                if (data.optJSONArray("datas") != null && data.optJSONArray("datas").length() > 0) {
                    data = data.optJSONArray("datas").optJSONObject(0);
                }
            }

            PropertiesComponentWarpper.useIntellijIdea = false;

            //找出json array
            if (jsonData.get("url").toString().contains("get_car_charge")) {
                System.out.println("a");
            }
            String arrayKeys = getAllArrayKeys(data);
            if (arrayKeys != null) {

                map.put("hasMoreInnerClass", true);
                List<Map<String, Object>> innerClassList = new ArrayList<>();
                String[] keys = arrayKeys.split(",");
                for (int i = 0; i < keys.length; i++) {
                    Map<String, Object> itemMap = new HashMap<>();
                    Object info = data.remove(keys[i]);
                    if (info instanceof JSONArray) {
                        JSONObject item = ((JSONArray) info).getJSONObject(0);
                        itemMap.put("name", keys[i].substring(0, 1).toUpperCase() + keys[i].substring(1));
                        List<FieldEntity> itemFields = convertBridge.createFields(item, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(item), new ClassEntity());
                        for (int j = itemFields.size() - 1; j >= 0; j--) {
                            if (itemFields.get(j).getType() == null || !StringUtils.isNotBlank(itemFields.get(j).getType())) {
                                itemFields.remove(j);
                            }
                        }
                        itemMap.put("columns", itemFields);
                        innerClassList.add(itemMap);
                    }
                }
                map.put("innerClassList", innerClassList);
            }

            List<FieldEntity> fields = convertBridge.createFields(data, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(data), new ClassEntity());
            for (int i = fields.size() - 1; i >= 0; i--) {
                if (fields.get(i).getType() == null || !StringUtils.isNotBlank(fields.get(i).getType())) {
                    fields.remove(i);
                }
            }
            map.put("columns", fields);
        }

        Object jsonReqObject = jsonData.get("paramJson");
        if (jsonReqObject != null) {
            JSONObject data = new JSONObject();
            if (jsonReqObject instanceof JSONArray) {
                data = ((JSONArray) jsonReqObject).getJSONObject(0);
            } else if (jsonReqObject instanceof String) {
                return null;
            } else {
                data = (JSONObject) jsonReqObject;
            }
            if (data == null) {
                return null;
            }

            PropertiesComponentWarpper.useIntellijIdea = false;

            //找出json array
            String arrayKeys = getAllArrayKeys(data);
            if (arrayKeys != null) {

                map.put("hasMoreInnerClassReq", true);
                List<Map<String, Object>> innerClassList = new ArrayList<>();
                String[] keys = arrayKeys.split(",");
                for (int i = 0; i < keys.length; i++) {
                    Map<String, Object> itemMap = new HashMap<>();
                    Object info = data.remove(keys[i]);
                    if (info instanceof JSONObject) {
                        JSONObject item = ((JSONArray) data.remove(keys[i])).getJSONObject(0);
                        itemMap.put("name", keys[i].substring(0, 1).toUpperCase() + keys[i].substring(1));
                        List<FieldEntity> itemFields = convertBridge.createFields(item, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(item), new ClassEntity());
                        for (int j = itemFields.size() - 1; j >= 0; j--) {
                            if (itemFields.get(j).getType() == null || !StringUtils.isNotBlank(itemFields.get(j).getType())) {
                                itemFields.remove(j);
                            }
                        }
                        itemMap.put("columnsReq", itemFields);
                        innerClassList.add(itemMap);
                    }
                }
                map.put("innerClassListReq", innerClassList);
            }

            List<FieldEntity> fields = convertBridge.createFields(data, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(data), new ClassEntity());
            for (int i = fields.size() - 1; i >= 0; i--) {
                if (fields.get(i).getType() == null || !StringUtils.isNotBlank(fields.get(i).getType())) {
                    fields.remove(i);
                }
            }
            map.put("columnsReq", fields);
        }
        map.put("comments", tableEntity.getComments());
        map.put("className", tableEntity.getClassName());
        map.put("classNameReq", tableEntity.getClassName().replace("Dto", "RequestDto"));

        map.put("classname", "m" + tableEntity.getClassName());
        map.put("pathName", tableEntity.getClassName().toLowerCase());
        map.put("mainPath", mainPath);
        map.put("package", config.getString("package"));
        map.put("moduleName", config.getString("moduleName"));
        map.put("author", config.getString("author"));
        map.put("email", config.getString("email"));
        map.put("datetime", format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        VelocityContext context = new VelocityContext(map);
        Map<String, Object> result = new HashMap<>();
        result.put("autoCodeEntity", tableEntity);
        result.put("context", context);
        return result;
    }

    public static String format(Date date, String pattern) {
        DateFormat df = createDateFormat(pattern);
        return df.format(date);
    }

    private static DateFormat createDateFormat(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        TimeZone gmt = TimeZone.getTimeZone("GMT");
        sdf.setTimeZone(gmt);
        sdf.setLenient(true);
        return sdf;
    }

    public static int testIsArrayORObject(String sJSON) {
        /*
         * return 0:既不是array也不是object
         * return 1：是object
         * return 2 ：是Array
         */
        if (sJSON.startsWith("{")) {
            JSONObject object = new JSONObject(sJSON);
            return 1;
        } else if (sJSON.startsWith("[")) {
            JSONArray object = new JSONArray(sJSON);
            return 2;
        } else {
            System.out.println("非法的JSON字符串");
            return 0;
        }

    }

    public static String getAllArrayKeys(JSONObject test) throws JSONException {

        String result = null;

        Iterator keys = test.keys();
        while (keys.hasNext()) {

            try {

                String key = keys.next().toString();
                String value = test.optString(key);

                int i = testIsArrayORObject(value);

                if (i == 2) {

                    result = "," + key;
                    System.out.println("i=2 | key=" + key + "| result=" + result);
//                    JSONArray arrays = new JSONArray(value);
//                    for (int k = 0; k < arrays.length(); k++) {
//                        JSONObject array = new JSONObject(arrays.get(k));
//                        result = getKeys(array) + ",";
//                    }
                }


            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        if (result != null) {
            result = result.substring(1);
        }

        return result;
    }


    /**
     * 生成代码
     */
    public static void generatorCode(Map<String, Object> jsonData) throws Exception {

        //获取模板列表
        Map<String, Object> data = covertDataEntity(null, jsonData);
        if (data == null) {
            return;
        }
        AutoCodeEntity tableEntity = (AutoCodeEntity) data.get("autoCodeEntity");
        VelocityContext context = (VelocityContext) data.get("context");
        Configuration config = getConfig();
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            String fileName = getFileName(true, template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"));
            if (fileName == null) {
                continue;
            }
            if (!new File(fileName).exists()) {
                new File(new File(fileName).getParent()).mkdirs();
                new File(fileName).createNewFile();
            }
            try {
                Files.write(Paths.get(fileName), sw.toString().getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
//            try {
//                //添加到zip
//                zip.putNextEntry(new ZipEntry(fileName));
//                IOUtils.write(sw.toString(), zip, "UTF-8");
//                zip.closeEntry();
//            } catch (IOException e) {
//               e.printStackTrace();
//            }
        }
    }


    /**
     * 获取配置信息
     */
    public static Configuration getConfig() {

        try {
            PropertiesConfiguration configuration = new PropertiesConfiguration();
            String path = Paths.get("", "generator.properties").toAbsolutePath().toString();
            configuration.load(new FileInputStream(path));
            return configuration;
        } catch (ConfigurationException | FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 获取文件名
     */
    public static String getFileName(boolean autoCreate, String template, String className, String packageName, String moduleName) {
        String packagePath = "src" + File.separator + "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(packageName)) {
            packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
        }

        if (autoCreate) {

            if (template.equals(".java.vm")) {
                return packagePath + "entity" + File.separator + className + ".java";
            }
            if (template.equals("RequestDto.java.vm")) {
                className = className.replace("Dto", "");
                return packagePath + "entityReq" + File.separator + className + "RequestDto.java";
            }

//            if (template.contains("Service.java.vm")) {
//                return packagePath + "service" + File.separator + className + "Service.java";
//            }


//            if (template.contains("ServiceImpl.java.vm")) {
//                return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
//            }

            if (template.contains("Controller.java.vm")) {
                return packagePath + "controller" + File.separator + className + "Controller.java";
            }
        } else {
            if (template.equals("CouponService.java.vm")) {
                return packagePath + "test" + File.separator + "CouponService.java";
            }

            if (template.equals("Test.java.vm")) {
                return packagePath + "test" + File.separator + className + ".java";
            }

            if (template.equals("TestMap.java.vm")) {
                return packagePath + "test" + File.separator + className + "Map.java";
            }

            if (template.equals("Strage2Map.java.vm")) {
                return packagePath + "test" + File.separator + className + "Strage2Map.java";
            }
            if (template.equals("serviceToMap.java.vm")) {
                return packagePath + "test" + File.separator + className + "serviceToMap.java";
            }

            if (template.contains("TestController.java.vm")) {
                return packagePath + "controller" + File.separator + className + "TestController.java";
            }
        }


        return null;
    }

    private static String splitInnerName(String name) {
        name = name.replaceAll("\\.", "_");
        return name;
    }

    public static String getReturnType(Map<String, Object> jsonData) {
        Object jsonObject = jsonData.get("responseJson");
        String Class = (String) jsonData.get("dtoName");

        int type = 1;// 1 object 2 array  3 page  4 String
        if (jsonObject != null) {
            JSONObject data = new JSONObject();
            if (jsonObject instanceof JSONArray) {
                data = ((JSONArray) jsonObject).getJSONObject(0);
                type = 2;
            } else if (jsonObject instanceof String) {
                type = 4;
            } else {
                data = (JSONObject) jsonObject;
                if (!data.keys().hasNext()) {
                    type = 5;
                }
            }
            if (StringUtils.isNotBlank(data.optString("isFirstPage"))) {
                type = 3;
            }

        } else {
            type = 4;
        }
        if ("true".equals(jsonData.get("hasPage"))) {
            type = 3;
        }
        if (type == 4) { // 1 object 2 array  3 page  4 String
            return "String";
        }else if (type == 5) {
            return "ResultDto";
        }  else if (type == 3) {
            return "PageResultDto<" + Class + ">";
        } else if (type == 2) {
            return "List<" + Class + ">";
        } else {
            return Class;
        }
    }

    public static void generatorMethodCode(List<Map<String, Object>> iteL) throws Exception {
        if (iteL.isEmpty()) {
            return;
        }
        //获取模板列表
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> methods = new ArrayList<>();
        for (int i = 0; i < iteL.size(); i++) {
            Map<String, Object> item = iteL.get(i);
            Map<String, Object> method = new HashMap<>();
            String url = (String) item.get("url");
            if (url == null) {
                continue;
            }
            if (url.contains("sendCoupon")) {
                continue;
            }

            if (url.contains("memberCouponsListUnDeal")) {
                continue;
            }
            if (url.contains("marketing/stamp/list.do")) {
                continue;
            }

            if (url.contains("labellingByMobile .do")) {
                continue;
            }
            String returnType = getReturnType(item);
            method.put("returnType", returnType);
            if (returnType.startsWith("PageResultDto")) {
                method.put("hasPage", true);
                method.put("returnType2", returnType.replaceAll("PageResultDto", "PageInfoDto"));
            } else {
                method.put("returnType2", returnType);
            }

            String name = url.substring(item.get("url").toString().lastIndexOf("/") + 1).replace(".do", "");
            if (name.equals("list")) {
                url = url.replace("/list.do", "");
                name = url.substring(url.lastIndexOf("/") + 1) + "List";
            }
            if (item.get("methodType") != null) {
                method.put("name", item.get("methodType") + name);
            }else{
                method.put("name", name);
            }

            method.put("comment", item.get("title") + " " + item.get("desc"));
            method.put("url", item.get("url"));
            JSONArray paramList = (JSONArray) item.get("paramList");
            List<Map<String, Object>> paramListArray = new ArrayList<>();
            String paramStr = "";
            String paramStr2 = "";
            String paramStr3 = "";
            HashSet<String> keys = new HashSet<>();
            for (int j = 0; j < paramList.length(); j++) {
                JSONObject param = paramList.getJSONObject(j);
                Map<String, Object> itemParm = new HashMap<>();
                if (param.getString("name").toString().contains(".")) {
                    continue;
                }
                if (param.getString("name").toString().contains("以下是")) {
                    continue;
                }
                if (!keys.add(param.getString("name"))) {
                    continue;
                }

                itemParm.put("name", param.getString("name"));
                String type = param.getString("type");
                if (type.equals("Int")) {
                    type = "int";
                } else if (type.equals("Timestamp")) {
                    type = "String";
                } else if (type.equals("Intenger")) {
                    type = "Integer";
                } else if (type.equals("number")) {
                    type = "BigDecimal";
                } else if (type.equals("number []")) {
                    type = "List<String>";
                } else if (type.equals("integer")) {
                    type = "Integer";
                } else if (type.equals("int")) {
                    type = "Integer";
                } else if (type.equals("Object []")) {
                    type = "List<Map>";
                } else if (type.equals("object []")) {
                    type = "List<Map>";
                } else if (type.equals("Object")) {
                    type = "Map";
                } else if (type.equals("bigDecimal") || type.equals("BigDecimal") || type.contains("Bigdecimal")) {
                    type = "String";
                } else if (type.equals("string")) {
                    type = "String";
                }else if (type.equals("string(200)")) {
                    type = "String";
                }else if (type.equals("string(256)")) {
                    type = "String";
                }else if (type.equals("string(64)")) {
                    type = "String";
                }else if (type.equals("string(32)")) {
                    type = "String";
                }else if (type.equals("string(10)")) {
                    type = "String";
                }else if (type.equals("string(20)")) {
                    type = "String";
                } else if (type.equals("String(255)")) {
                    type = "String";
                }else if (type.equals("string(512)")) {
                    type = "String";
                }else if (type.equals("String(36)")) {
                    type = "String";
                }else if (type.equals("Base64String")) {
                    type = "String";
                }else if (type.equals("int(10)")) {
                    type = "String";
                }else if (type.equals("string(16)")) {
                    type = "String";
                }else if (type.equals("sring")) {
                    type = "String";
                }
                itemParm.put("type", type);
                itemParm.put("require", param.getString("require"));
                itemParm.put("requireBool", param.getString("require") == "是" ? true : false);
                itemParm.put("desc", param.getString("desc"));
                paramListArray.add(itemParm);
                paramStr += ", " + itemParm.get("type") + " " + itemParm.get("name");
                paramStr2 += ", " + itemParm.get("name");
                paramStr3 += ", " + "@RequestParam(\"" + itemParm.get("name") + "\") " + itemParm.get("type") + " " + itemParm.get("name");
            }
            if (paramStr.length() > 0) {
                paramStr = paramStr.substring(1);
            }
            if (paramStr2.length() > 0) {
                paramStr2 = paramStr2.substring(1);
            }
            if (paramStr3.length() > 0) {
                paramStr3 = paramStr3.substring(1);
            }
            method.put("classNameReq", item.get("dtoName").toString().replace("Dto", "RequestDto"));
            method.put("paramStr", paramStr);
            method.put("paramStr2", paramStr2);
            method.put("paramStr3", paramStr3);
            method.put("paramList", paramListArray);
            if (paramListArray.size() > 5) {
                //参数超过5个 使用Dto方式
                method.put("hasMoreParam", true);
            }
            method.put("isPost", "POST".equals(item.get("method")) ? true : false);
            method.put("type", "POST".equals(item.get("method")) ? "HttpMethod.POST" : "HttpMethod.GET");
            methods.add(method);
        }
        map.put("methods", methods);
        Map<String, Object> data = covertDataEntity(map, iteL.get(0));

        if (data == null) {

            return;
        }

        AutoCodeEntity tableEntity = (AutoCodeEntity) data.get("autoCodeEntity");
        VelocityContext context = (VelocityContext) data.get("context");
        Configuration config = getConfig();
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            String fileName = getFileName(false, template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"));
            if (fileName == null) {
                continue;
            }
            if (!new File(fileName).exists()) {
                new File(new File(fileName).getParent()).mkdirs();
                new File(fileName).createNewFile();
            }
            try {
                Files.write(Paths.get(fileName), sw.toString().getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
//            try {
//                //添加到zip
//                zip.putNextEntry(new ZipEntry(fileName));
//                IOUtils.write(sw.toString(), zip, "UTF-8");
//                zip.closeEntry();
//            } catch (IOException e) {
//               e.printStackTrace();
//            }
        }
    }
}
